from django import forms
from django.core.exceptions import ObjectDoesNotExist
from django.utils.datastructures import SortedDict
from opinion_extractor.respondent.utils import get_latest_respondent_profile
import exceptions
import models


def get_latest_respondent_profile_for_questionnaire(user, questionnaire):
    try:
        return get_latest_respondent_profile(
            user, 
            questionnaire.get_population_filter_as_Q_object()
        )
    except ObjectDoesNotExist:
        raise exceptions.UserNotInPopulation(user, questionnaire)


def get_questionnaires_for_user(user):
    from opinion_extractor.questionnaire.models import Questionnaire
    questionnaires = []
    for q in Questionnaire.published.all():
        try:
            get_latest_respondent_profile_for_questionnaire(user, q)
            questionnaires.append(q)
        except exceptions.UserNotInPopulation:
            pass
    return questionnaires


def get_opinion_form(user, questionnaire):
    try:
        old_opinion = models.Opinion._default_manager.filter(
            user=user, questionnaire=questionnaire
        ).latest()
    except ObjectDoesNotExist:
        old_opinion = None # User didn't have an opinion on this questionnaire before
    fields = SortedDict()
    for x, question in enumerate(questionnaire.questions.all()):
        key = 'answer%d' % x
        fields[key] = forms.TypedChoiceField(
            choices=enumerate(question.answers),
            widget=forms.RadioSelect,
            label=question,
            initial=getattr(old_opinion, key, None),
            coerce=lambda val: int(val)
        )
    
    OpinionForm = type(
        'OpinionForm',
        (forms.BaseForm,),
        {'base_fields': fields}
    )
    
    def get_opinion(self):
        o = models.Opinion(user=user, questionnaire=questionnaire)
        for field_name in fields:
            setattr(o, field_name, self.cleaned_data[field_name])
        return o
    OpinionForm.get_opinion = get_opinion
    
    return OpinionForm
